/**
 * Copyright IBM Corp. 2016, 2025
 * SPDX-License-Identifier: BUSL-1.1
 */

import Model, { attr } from '@ember-data/model';
import { withFormFields } from 'vault/decorators/model-form-fields';
import { withModelValidations } from 'vault/decorators/model-validations';
import { withExpandedAttributes } from 'vault/decorators/model-expanded-attributes';
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
import { isPresent } from '@ember/utils';

const validations = {
  accountName: [
    {
      validator(model) {
        const { generate, accountName } = model;
        // this is required when generate is true
        return generate && !isPresent(accountName) ? false : true;
      },
      message: "Account name can't be blank when the key is generated by Vault.",
    },
    {
      type: 'containsWhiteSpace',
      message:
        "Account name contains whitespace. If this is desired, you'll need to encode it with %20 in API requests.",
      level: 'warn',
    },
  ],
  issuer: [
    {
      validator(model) {
        const { generate, issuer } = model;
        // this is required when generate is true
        return generate && !isPresent(issuer) ? false : true;
      },
      message: "Issuer can't be blank when when the key is generated by Vault.",
    },
  ],
  key: [
    {
      validator(model) {
        const { generate, key, url } = model;
        // this is required when generate is false and url is blank
        return !generate && !isPresent(url) && !isPresent(key) ? false : true;
      },
      message: "Key can't be blank if key is being passed from another service and the URL is empty.",
    },
  ],
  keySize: [{ type: 'number', message: 'Key size must be a number.' }],
  name: [
    { type: 'presence', message: "Name can't be blank." },
    {
      type: 'containsWhiteSpace',
      message:
        "Name contains whitespace. If this is desired, you'll need to encode it with %20 in API requests.",
      level: 'warn',
    },
  ],
  qrSize: [{ type: 'number', message: 'QR size must be a number' }],
};

@withModelValidations(validations)
@withExpandedAttributes()
@withFormFields()
export default class TotpKeyModel extends Model {
  @attr('string', {
    readOnly: true,
  })
  backend;

  @attr('string', {
    subText: 'Specifies the name for this key.',
  })
  name;

  @attr('string', {
    subText: 'The name of the account associated with the key. Required for keys generated by Vault.',
  })
  accountName;

  @attr('string', {
    possibleValues: ['SHA1', 'SHA256', 'SHA512'],
    defaultValue: 'SHA1',
  })
  algorithm;

  @attr('number', {
    possibleValues: [6, 8],
    defaultValue: 6,
  })
  digits;

  @attr('string', {
    subText: `The name of the key's issuing organization. Required for keys generated by Vault.`,
  })
  issuer;

  @attr({
    editType: 'ttl',
    helperTextEnabled: 'How long each generated TOTP is valid.',
    defaultValue: 30, // API accepts both an integer as seconds and string with unit e.g 30 || '30s'
  })
  period;

  // The generate attr is a boolean. The generateString getter and setter is used only in forms to get and set the boolean via
  // strings values. The payload params expect the attr to be a boolean value.
  @attr({
    label: 'Key Provider',
    defaultValue: true,
    editType: 'radio',
    possibleValues: ['Vault', 'Other service'],
    fieldValue: 'generateString',
    subText: 'Specifies if the key should be generated by Vault or passed from another service.',
  })
  generate;

  // Used when generate is true
  @attr('number', {
    defaultValue: 20,
  })
  keySize;

  @attr('number', {
    possibleValues: [0, 1],
    defaultValue: 1,
  })
  skew;

  @attr('boolean', {
    editType: 'toggleButton',
    defaultValue: true,
    helperTextDisabled: 'Vault will not return QR code and url upon key creation.',
    helperTextEnabled: 'QR code and URL will be returned upon generating a key.',
  })
  exported;

  @attr('number', {
    label: 'QR size',
    defaultValue: 200,
  })
  qrSize;

  // Used when generate is false
  @attr('string', {
    label: 'URL',
    helpText:
      'If a URL is provided the other fields can be left empty. E.g. otpauth://totp/Vault:test@test.com?secret=<your_secret>&issuer=Vault',
    subText: 'The TOTP key url string that can be used to configure a key.',
  })
  url;

  @attr('string', {
    subText: 'The root key used to generate a TOTP code.',
  })
  key;

  // Returned when a key is created as provider
  @attr('string', {
    readOnly: true,
  })
  barcode;

  get attrs() {
    const keys = ['accountName', 'name', 'algorithm', 'digits', 'issuer', 'period'];
    return keys.map((k) => this.allByKey[k]);
  }

  get generatedAttrs() {
    const keys = ['url'];
    return keys.map((k) => this.allByKey[k]);
  }

  get generateString() {
    return this.generate ? 'Vault' : 'Other service';
  }

  set generateString(value) {
    this.generate = value === 'Vault' ? true : false;
  }

  @lazyCapabilities(apiPath`${'backend'}/keys/${'id'}`, 'backend', 'id') keyPath;

  get canDelete() {
    return this.keyPath.get('canDelete');
  }

  get canRead() {
    return this.keyPath.get('canRead');
  }
}
